package ttk.muxiuesd.entity;

import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.utils.Disposable;
import com.badlogic.gdx.utils.viewport.Viewport;
import ttk.muxiuesd.OrthographicCameraController;
import ttk.muxiuesd.entity.bullet.Bullet;
import ttk.muxiuesd.entity.bullet.BulletFire;
import ttk.muxiuesd.event.EntityDead;
import ttk.muxiuesd.event.SlimeDeadEvent;
import ttk.muxiuesd.gameinterface.Drawable;
import ttk.muxiuesd.gameinterface.Updateable;
import ttk.muxiuesd.screen.MainGameScreen;
import ttk.muxiuesd.util.Direction;
import ttk.muxiuesd.util.Log;
import ttk.muxiuesd.util.Position;
import ttk.muxiuesd.util.Util;
import ttk.muxiuesd.world.MainWorld;

import java.util.ArrayList;
import java.util.List;

/**
 * 实体组
 * */
public class EntityGroup implements Disposable, Updateable, Drawable {
    private final String TAG = this.getClass().getName();

    public MainWorld world;
    public Player player;

    private List<Entity> _delayAdd = new ArrayList<>();
    private List<Entity> _delayRemove = new ArrayList<>();

    private List<Entity> entities = new ArrayList<>();

    private List<Entity> enemyEntity = new ArrayList<>();
    private List<Bullet> playerBulletEntity = new ArrayList<>();
    private List<Bullet> enemyBulletEntity = new ArrayList<>();

    private List<Entity> updatableEntity = new ArrayList<>();
    private List<Entity> drawableEntity = new ArrayList<>();

    public EntityDead entityDead = new EntityDead();

    private Batch batch;
    public Viewport viewport;
    public OrthographicCameraController cameraController;

    public EntityGroup(MainWorld world) {
        this.world = world;
        MainGameScreen gameScreen = world.getGameScreen();
        this.batch = gameScreen.batch;
        this.viewport = gameScreen.viewport;
        this.cameraController = gameScreen.cameraController;

        //添加史莱姆死亡事件
        this.entityDead.addEvent(new SlimeDeadEvent());
    }

    /*public EntityGroup(MainGameScreen gameScreen) {
        this.batch = gameScreen.batch;
        this.viewport = gameScreen.viewport;
        this.cameraController = gameScreen.cameraController;

        //添加史莱姆死亡事件
        this.entityDead.addEvent(new SlimeDeadEvent());
    }*/

    public void add(Entity entity) {
        _delayAdd.add(entity);
    }

    public void remove(Entity entity) {
        _delayRemove.add(entity);
    }

    /**
     * 延迟添加实体防止并发修改异常
     *
     * @param entity 实体
     */
    private void _add(Entity entity) {
        if (entity instanceof Player) {
            this.player = (Player) entity;
        } else if (entity instanceof Bullet) {
            Bullet bullet = (Bullet) entity;
            if (bullet.group == Group.player) {
                this.playerBulletEntity.add(bullet);
            }
            if (bullet.group == Group.enemy) {
                this.enemyBulletEntity.add(bullet);
            }
        } else if (entity.group == Group.enemy) {
            this.enemyEntity.add(entity);
        }
        try {
            if (entity.getClass().getMethod("update", float.class) != null) {
                updatableEntity.add(entity);
            }
        } catch (NoSuchMethodException ignore) {

        }
        try {
            if (entity.getClass().getMethod("draw", Batch.class) != null) {
                drawableEntity.add(entity);
            }
        } catch (NoSuchMethodException ignore) {

        }
        this.entities.add(entity);
    }

    /**
     * 延迟移除实体防止并发修改异常
     *
     * @param entity 实体
     */
    private void _remove(Entity entity) {
        if (player != null && player.id == entity.id) {
            player = null;
        }

        this.enemyEntity.remove(entity);
        this.playerBulletEntity.remove(entity);
        this.enemyBulletEntity.remove(entity);

        this.updatableEntity.remove(entity);
        this.drawableEntity.remove(entity);
        this.entities.remove(entity);
    }

    public Bullet createBullet(Entity from, Direction direction) {
        BulletFire bullet = new BulletFire(this, from.group);
        bullet.setPosition(from.x + (from.width - bullet.width) / 2, from.y + (from.height - bullet.height) / 2);
        bullet.setDirection(direction.getxDirection(), direction.getyDirection());
        bullet.setCullingArea(bullet.x, bullet.y, bullet.width, bullet.height);
        return bullet;
    }

    /**
     * 游戏核心逻辑更新
     * */
    public void update(float delta) {
        // 玩家存活才检测所有碰撞！！！
        if (!this.playerIsDeath()) {
            if (!_delayRemove.isEmpty()) {
                for (Entity entity : _delayRemove) {
                    _remove(entity);
                    //实体死亡事件执行
                    this.entityDead.handle(this, entity);
                }
                _delayRemove.clear();
            }
            if (!_delayAdd.isEmpty()) {
                for (Entity entity : _delayAdd) {
                    _add(entity);
                }
                _delayAdd.clear();
            }

            for (Entity entity : updatableEntity) {
                entity.update(delta);
            }
            // 敌人与子弹碰撞检测
            for (Bullet playerBullet : playerBulletEntity) {
                if (playerBullet.getLiveTime() > playerBullet.getMaxLiveTime()) {
                    this.remove(playerBullet);
                    continue;
                }
                for (Entity enemy : enemyEntity) {
                    if (playerBullet.hurtbox.overlaps(enemy.hurtbox)
                        || enemy.hurtbox.overlaps(playerBullet.hurtbox)) {
                        enemy.curHealth -= playerBullet.damage;
                        enemy.attacked = true;
                        playerBullet.setLiveTime(playerBullet.getMaxLiveTime());
                        //Log.print(TAG, "敌人扣血：" + playerBullet.damage + " 目前血量：" + enemy.curHealth);
                    }
                }
            }
            // 玩家与子弹碰撞检测
            for (Bullet enemyBullet : enemyBulletEntity) {
                if (enemyBullet.getLiveTime() > enemyBullet.getMaxLiveTime()) {
                    this.remove(enemyBullet);
                }
                //玩家防御
                if (player.isDefend) {
                    float distance = Util.getDistance(player, enemyBullet);
                    if (distance <= player.defenseRadius) {
                        this.remove(enemyBullet);
                        continue;
                    }
                }

                if (enemyBullet.hurtbox.contains(player.hurtbox)
                    || player.hurtbox.contains(enemyBullet.hurtbox)) {
                    player.curHealth -= enemyBullet.damage;
                    enemyBullet.setLiveTime(enemyBullet.getMaxLiveTime());
                    this.player.attacked = true;
                    //Log.print(TAG, "玩家扣血：" + enemyBullet.damage + " 目前血量：" + player.curHealth);
                }
            }
        } else {
            // 玩家死亡
            Log.print(TAG, "玩家死亡！按下F1重新开始");
            return;
        }
        //使相机跟随鼠标移动
        Direction direction = Util.getDirection();
        Position position = Util.getMousePosition();
        float xOffset = Math.abs(position.x) * direction.getxDirection() / 200;
        float yOffset = Math.abs(position.y) * direction.getyDirection() / 200;
        this.cameraController.setPosition(player.x + player.width / 2 + xOffset,
            player.y + player.height / 2 + yOffset);
    }

    public void draw(Batch batch) {
        for (Entity entity : drawableEntity) {
            entity.draw(batch);
        }
    }

    public void resize(int width, int height){
        viewport.setWorldSize(width, height);
        cameraController.resize(width, height);
    }

    @Override
    public void dispose() {
        for (Entity entity : this.entities) {
            entity.dispose();
        }
    }

    public boolean playerIsDeath () {
        return player.curHealth <= 0;
    }
}
